#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 128
#define MAX 100
#define INFO(fmt,...) printf("file:[%s],line:[%d]"fmt,__FILE__,__LINE__,##__VA_ARGS__);

int main(int argc,const char* argv[])
{
    if(argc != 3){
        INFO("argc is invalid,argc must be 3");
        exit(-1);
    }

    int sockfd = -1;
    int acceptfd = -1;
    struct sockaddr_in serveraddr,clientaddr;
    struct sockaddr_in clientaddrs[MAX];
    socklen_t len = sizeof(serveraddr);

    memset(&serveraddr,0,sizeof(serveraddr));

    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1){
        INFO("socket is failed!");
        exit(-1);
    }

    serveraddr.sin_family= AF_INET;
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    serveraddr.sin_port=htons(atoi(argv[2]));

    if(bind(sockfd,(struct sockaddr*)&serveraddr,len)==-1){
        INFO("bind is failed!");
        exit(-1);
    }

    if(listen(sockfd,5)==-1){
        INFO("listen is failed!");
        exit(-1);
    }
    char buf[N]={0};
    struct pollfd fd[MAX]={0};
    nfds_t nfds=MAX;
    ssize_t recvbytes;

    fd[0].fd=sockfd;
    fd[0].events=POLLIN;

    for(int i=1;i<MAX;i++){
        fd[i].fd=-1;
    }

    while(1){
        if(poll(fd,nfds,-1)==-1){
            INFO("poll is failed");
            exit(-1);
        }

        if(fd[0].revents & POLLIN){
            acceptfd=accept(sockfd,(struct sockaddr*)&clientaddr,&len);
            if(acceptfd==-1){
                INFO("accept is failed");
                exit(-1);
            }
            printf("Client:[%s,%d]Linked\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));

            for(int i=1;i<MAX;i++){
                if(fd[i].fd==-1){
                    fd[i].fd=acceptfd;
                    fd[i].events=POLLIN;
                    clientaddrs[i]=clientaddr;
                    break;
                }
            }
        }

        for(int i=1;i<MAX;i++){
            memset(buf,0,sizeof(buf));
            if(fd[i].fd!=-1&&fd[i].revents&POLLIN){
                recvbytes=recv(fd[i].fd,buf,sizeof(buf),0);
                if(recvbytes==-1){
                    INFO("recv is failed");
                    exit(-1);
                }else if(recvbytes==0||strcmp(buf,"**quit**")==0){
                    printf("Client:[%s,%d]Exit\n",inet_ntoa(clientaddrs[i].sin_addr),ntohs(clientaddrs[i].sin_port));
                    close(fd[i].fd);
                    fd[i].fd=-1;
                    continue;
                }
                
                printf("Client:[%s,%d]buf=%s\n",inet_ntoa(clientaddrs[i].sin_addr),ntohs(clientaddrs[i].sin_port),buf);
                strcat(buf,"^_^");
                send(fd[i].fd,buf,sizeof(buf),0);
            }
        }
    }

    return 0;
}